#!/usr/bin/env perl

# Run multiple benchs on a given mesh (.node and .ele), for a given partitioner, a given platform (wmap file if pagrid) and a number of partitions. Get the relevant statistics.
# This file is a wrapper to a number of simpler scripts.

# For the Wrekagrid project,
# Basile Clout, November 2007

use Getopt::Long;
use File::Basename;
use File::Copy;

use strict;
use warnings;

sub usage {
  print <<EOF;

Usage: runBenchs.pl [-i input file(s) type: triangle, gmsh, gts] [-p
partitioner: pagrid, metis, jostle, scotch] [-n number of partitions]
[-m number of kambiz bench by partition] [-d directory to create
files] [-l log file] [-h print this help] [-r Ref ratio
(DEFAULT=0.01)] [-gr number of partitions to be graphically
represented] [-u user to run the bench as] [-s add G and R to the list
file] [--fast Use metis' mesh2nodal] [-G pagrid G parameter] [--list
text file containing partitions to bench] [--fast Generate graph with
metis' mesh2nodal] <file1> [<file2>] [<arg>]

Example: runBenchs.pl -i triangle -p pagrid -n 50 -m 0 -u basil
-G 10 -r 0.01 --fast -d ./first_try -s -gr 0
testix.1.node testix.1.ele /home/basil/parts/wmaps/cano_cpu/wmap01.out

EOF
exit;
}

my $ele2mesh_bin="/root/export_cluster/code/tools/wmesh/ele2mesh.awk";
#my $ele2mesh_bin="/Users/basileclout/Desktop/repo/wmesh/ele2mesh.awk";
my $mesh2graph_bin="/root/export_cluster/code/tools/wmesh/test_mesh/mesh2graph.py";
my $mesh2graph_metis_bin="/export/home/basil/config/export_cluster/code/partitioners/metis/metis-4.0/mesh2nodal";
#my $mesh2graph_bin="/Users/basileclout/Desktop/repo/wmesh/test_mesh/mesh2graph.py";
my $genpart_bin="/root/export_cluster/code/tools/generate_part.pl";
#my $genpart_bin="/Users/basileclout/Desktop/repo/generate_part.pl";
my $drawparts_bin="/root/export_cluster/code/tools/drawParts.pl";
#my $drawparts_bin="/Users/basileclout/Desktop/repo/drawParts.pl";
my $evalParts_bin="/root/export_cluster/code/tools/evalParts.pl";
my $setRef="/root/export_cluster/code/tools/setRef.sh";

my $tgraph=0;		# 0 means nodal graph, 1 means dual
my $tmp_dir="/tmp";		# tmp directory for creating intermediary files

my $logfile = "runBench.log";
my ($n, $m, $g) = (1, 1, 0);
my $dir=".";
my $help;
my $type="triangle";
my $part="metis";
my ($f1, $f2, $farg);
my $user = "root";
my $fast;
my $rref=0.01;
my $flist="bestparts.txt";

my ($basename, $dummy)=("","");
my ($meshname, $fnode, $fgraph) =("","","");
my $onode="";			# Original node file corresponding to the mesh (=.node for triangle, but not for other format)

my $pagrid_fl="-r";
my $s;
my $pG=10;

GetOptions("i=s"=>\$type, "p=s"=>\$part, "n=i"=>\$n, "m=i"=>\$m, "r=f"=>\$rref, "gr=i"=>\$g, "d=s"=>\$dir, "u=s"=>\$user, "l=s"=>\$logfile, "G=i"=>\$pG, "h"=>\$help, "fast"=>\$fast, "list=s"=>\$flist, "s"=>\$s);

usage() if ($help);
$mesh2graph_bin=$mesh2graph_metis_bin if ($fast);

# If input type is triangle, 3 arguments are expected
if ($type =~ /[tT]riangle/){
  if ($#ARGV != 2){
    die "ERROR: Triangle input type: runBench.pl [options] <.node file> <.ele file> <partitioner arg>";
  }else{
    $f1=$ARGV[0];
    $f2=$ARGV[1];
    $farg=$ARGV[2];
    die "ERROR: Impossible to read .node file $f1: $!" if (! -r $f1);
    die "ERROR: Impossible to read .ele file $f2: $!" if (! -r $f2);
    if ($part =~ /metis/){
      die "ERROR: Triangle input type: the third argument $farg must be a positive integer!\n" if ($farg !~ /^\d+$/);
      die "ERROR: $farg is too many partitions!!\n" if ($farg > 1000);
    }elsif ($part =~ /pagrid/){
      die "ERROR: Impossible to read processor graph file $farg: $!" if (! -r $farg);
    }else{
      die "ERROR: $part unknown partitioner";
    }
    $onode=$f1;
    ($basename, $dummy) = fileparse($f2);
  }
}else{
  die("ERROR: Dont know $type input type yet!");
}

# Check partitioner
if ($part !~ /pagrid/ and $part !~ /metis/){
  die "ERROR: mesh partitioner $part not recognized~";
}

# Create list file if does not exist yet
open(MYLIST, ">$flist") if (! -r $flist);
close(MYLIST);

open LOG, ">$logfile" or die "Impossible to create log file $logfile: $!";
my ($sec, $min, $hrs, $day, $month, $year) = (localtime) [0,1,2,3,4,5];
my $date = sprintf("%04d-%02d-%02d %d:%d:%d\n", $year+1900, $month+1, $day, $hrs, $min, $sec);
print LOG "runBench log file, created on $date\n";

# Check given directory syntax ad create it
if ($dir !~ /^\.*\// and $dir ne "."){
  $dir="./$dir";
}
if ($dir =~ /(.*)\/$/){
  $dir=$1;
}
if (! -d $dir){
  mkdir $dir;
  print LOG "Directory $dir created!\n";
}

# Create mesh file, common input for creating graph files
if ($type =~ /[[tT]riangle/){
  my @splitname=split /\./,$basename;
  if ($splitname[$#splitname] eq "ele"){
    splice @splitname, $#splitname, 1;
  }
  $basename=join('.',@splitname);
  $meshname = "${dir}/${basename}.mesh";
  system("$ele2mesh_bin < $f2 > $meshname") == 0 or die "Impossible to transform .ele file $f2 in mesh file. Check syntax: $!";
  print LOG "Mesh file $meshname created!\n";
  
}else{
  die "ERROR: Dont know this input file type yet";
}


# Create graph
my @split_meshname=split /\./, $meshname;
my $switch;

if($fast){
  open(GRAPH, "$mesh2graph_bin $meshname |") or die "Impossible to create graph file: $!";
}else{
  $switch="-n";
  $switch="-d" if ($tgraph != 0);
  open(GRAPH, "$mesh2graph_bin $switch $onode $meshname |") or die "Impossible to create graph files: $!";
}

my @graph_content=<GRAPH>;
print LOG join('', @graph_content);
close(GRAPH);

if (!$fast){
  if ($switch eq "-n"){
    $split_meshname[$#split_meshname]="nnode";
    $fnode=join('.', @split_meshname);
    $split_meshname[$#split_meshname]="ngraph";
    $fgraph=join('.', @split_meshname);
    print LOG "Nodal graph files $fnode and $fgraph created!\n";
  }else{
    $split_meshname[$#split_meshname]="dnode";
    $fnode=join('.', @split_meshname);
    $split_meshname[$#split_meshname]="dgraph";
    $fgraph=join('.', @split_meshname);
    print LOG "Dual graph files $fnode and $fgraph created!\n";
  }
}else{				# Use Metis' mesh2nodal function (a lot faster, but no coordinates for the mesh2dual
  $split_meshname[$#split_meshname]="ngraph";
  $fgraph=join('.', @split_meshname);
  move "${meshname}.ngraph", $fgraph or die "Impossible to rename output of metis\' mesh2nodal to $fgraph: $!";
  print LOG "Nodal graph file $fgraph created!\n";
}

# Create partitions 
my $gen_order="";
my @gen_result;
my $list = "";
my $farg_tmp="";
my $setOrder="";

print "Partitions generation stats:\n" if ($part =~ /pagrid/i);
if ($part =~ /metis/){
  $list = "${dir}/$f1.metis.list.txt";
  $gen_order = "$genpart_bin -p metis -d $dir/partitions -n $n -o $list $fgraph $farg";
}elsif($part =~ /pagrid/){
  $list = "${dir}/$f1.pagrid.list.txt";
  $farg_tmp=$farg.".tmp";
  $setOrder="$setRef $rref < $farg > $farg_tmp";
  system($setOrder); # or die("Impossible to change the Rref in $farg to $rref in $farg_tmp with order \"$setOrder\": $!");
  $gen_order = "$genpart_bin -p pagrid -d $dir/partitions -n $n -o $list --list $flist -G $pG $fgraph $farg_tmp";
  print "G = $pG\n";
}else{
  die "ERROR: dont know this partitioner $part for now ...";
}

open(GEN, "$gen_order |") or die "Impossible to generate partitions: $!";
@gen_result=<GEN>;
print LOG "Partitions generated with order \n\t$gen_order\n";
print LOG join('', @gen_result);
print join('', @gen_result);
close(GEN);

unlink $farg_tmp or die("Impossible to delete $farg_tmp: $!");

if ($s){
  my $list_tmp="${list}.tmp";
  open LIST, $list or die "Impossible to open generated list $list: $!";
  my @list_content=<LIST>;
  chomp @list_content;
  open LISTTMP, ">$list_tmp";
  for my $row (@list_content){
    print LISTTMP "$row\t\t${pG}\t${rref}\n";
  }
  close(LIST);
  close(LISTTMP);
  rename $list_tmp, $list or die "Impossible to rename $list_tmp tp $list: $!";
}



# Draw some partitions if asked

my $draw_order="";
my @draw_content;
if ($g>0){
  $draw_order="$drawparts_bin -d ${dir}/draws -n $g -f $list -p $fnode $fgraph";
  open(DRAW, "$draw_order |") or die "Impossible to draw partitions: $!";
  @draw_content=<DRAW>;
  print LOG join('', @draw_content),"\n";
  close(DRAW);
}


# Run benchs
if ($m>0){
  print "Benchs results: \n";
  print LOG "Bench results: \n";
  my $eval_order="$evalParts_bin -f $list -l ${dir}/eval.log -n $m -u $user $onode $f2";
  open(BENCH, "$eval_order |") or die "Impossible to launch kambiz's benchs: $!";
  my @eval_content=<BENCH>;
  print LOG join('',@eval_content);
  print join('', @eval_content);
  close(BENCH);
}


  



